﻿namespace Oddo.Concept.Crm.Common.Behaviors
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Transactions;
    using Microsoft.Practices.Unity.InterceptionExtension;

    public class TransactionBehavior : IInterceptionBehavior
    {
        private readonly TraceSource _trace = new TraceSource("TransactionBehavior");

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            string transactionId = null;
            var current = Transaction.Current;
            var isRoot = current == null;
            transactionId = isRoot ? null : current.TransactionInformation.LocalIdentifier;

            using(var scope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions{ IsolationLevel = IsolationLevel.ReadCommitted, Timeout = TransactionManager.DefaultTimeout}))
            try
            {
                if (isRoot)
                {
                    transactionId = Transaction.Current.TransactionInformation.LocalIdentifier;

                    if(_trace.Switch.ShouldTrace(TraceEventType.Verbose))
                        _trace.TraceEvent(TraceEventType.Verbose, 0,
                                          string.Format("Creating transaction Id: {0}, Isolation: {2}, Status: {1}",
                                                        Transaction.Current.TransactionInformation.LocalIdentifier,
                                                        Transaction.Current.TransactionInformation.Status,
                                                        Transaction.Current.IsolationLevel));
                   
                }

                var methodReturn = getNext().Invoke(input, getNext);
                if (methodReturn.Exception == null)
                {
                    scope.Complete();
                    if (isRoot && _trace.Switch.ShouldTrace(TraceEventType.Verbose))
                        _trace.TraceEvent(TraceEventType.Verbose, 0, string.Format("Transaction Id: {0} completed", transactionId));
                }
                else
                {
                    if (isRoot && _trace.Switch.ShouldTrace(TraceEventType.Verbose))
                        _trace.TraceEvent(TraceEventType.Verbose, 0, string.Format("Transaction Id: {0} aborted", transactionId));    
                }
                return methodReturn;
            }
            catch (Exception)
            {
                if (isRoot && _trace.Switch.ShouldTrace(TraceEventType.Verbose))
                    _trace.TraceEvent(TraceEventType.Verbose, 0, string.Format("Transaction Id: {0} exception", transactionId));    
                throw;
            }
        }

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
}